package com.synnex.wmsdeployer.util;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;

/**
 * CopyZipFile.java - Created on 2011-5-13
 * 
 * Copyright 2011 SYNNEX Information Technologies, Inc. All Rights Reserved.
 * 
 * version date who changes ------- ----------- -----------
 * --------------------------- 001 2011-5-13 lukelu Initial Version
 * 
 */

public class JarUtil {
    public static void main(String[] args) throws Throwable {
        long start=System.currentTimeMillis();
        copyFile("D:/jad/wmserver.ear", "D:/jad/deploy/11/wmserverTemp.ear");
        extractJarFromJar("D:/jad/deploy/11/wmserverTemp.ear", "wmbusiness","D:/jad/deploy/11/wmbusinessTemp.jar");
        mergeJarFile("D:/jad/deploy/11/wmbusinessTemp.jar", "D:/jad/src.jar","D:/jad/deploy/11/wmbusiness.jar");
        addJarToJarFile("D:/jad/deploy/11/wmserverTemp.ear", "D:/jad/deploy/11/wmserver.ear",new String[]{"D:/jad/deploy/11/wmbusiness.jar"});
//        copyJarFile("D:/jad/wmbusiness.jar", "D:/jad/wmbusiness_final.jar");
//        copyFile("d:/test.png", "d:/test1.png");
//        System.err.println(getInnerJarFile("D:/jad/wmserver.ear"));
        System.out.printf("Time elapsed:%d",System.currentTimeMillis()-start);
    }
    public static void extractJarFromJar(String src,String jarName,String dest) throws Throwable {
        JarInputStream zis = new JarInputStream(new FileInputStream(src));
        while (true) {
            JarEntry ze = (JarEntry) zis.getNextEntry();
            if (ze == null)
                break;
            String name = ze.getName();
            if (name.indexOf(jarName) > -1) {
                File destFile=new File(dest);
                FileOutputStream fos = new FileOutputStream(dest);
                copyStream(zis, fos);
                destFile.setLastModified(ze.getTime());
                fos.close();
            }
        }
    }
    
    public static void copyJarFile(String src,String dest) throws Throwable, IOException{
        JarInputStream zis = new JarInputStream(new FileInputStream(src));
        JarOutputStream zos = new JarOutputStream(new FileOutputStream(dest));
        long s = System.currentTimeMillis();
        while (true) {
            JarEntry ze = (JarEntry) zis.getNextEntry();
            if (ze == null)
                break;
            String name = ze.getName();
            System.err.println(name);
                byte[] buffer = new byte[1024];
                ByteArrayOutputStream bos=new ByteArrayOutputStream();
                while (true) {
                    int readSize = zis.read(buffer);
                    if (readSize == -1) break;
                    bos.write(buffer, 0, readSize);
                }
                bos.flush();
                System.err.println(ze.getSize()+" "+ze.getCompressedSize());
                System.err.println(bos.size());
                JarEntry je=new JarEntry(ze.getName());
                je.setTime(ze.getTime());
                zos.setLevel(6);
                zos.putNextEntry(je);
                zos.write(bos.toByteArray());
                zos.closeEntry();
        }
        zos.finish();
        zos.close();
        System.err.println(System.currentTimeMillis() - s);
    }
    public static void addJarToJarFile(String src,String outputFilePath,String... filePathToAdd) throws Throwable, IOException{
        addJarToJarFile(src, outputFilePath, "/", filePathToAdd);
    }
    public static void addJarToJarFile(String src,String outputFilePath,String fileSlash,String... filePathToAdd) throws Throwable, IOException{
        JarInputStream zis = new JarInputStream(new FileInputStream(src));
        JarOutputStream zos = new JarOutputStream(new FileOutputStream(outputFilePath));
        List<String> filePathToAddList=Arrays.asList(filePathToAdd);
        Map<String,String> fileNameMap=new HashMap<String,String>();
        for(String filePath:filePathToAddList){
            if(!new File(filePath).exists()){
                throw new IllegalArgumentException("File (%s) does not exist");
            }
            String fileShorName=filePath.substring(filePath.lastIndexOf(fileSlash)+1, filePath.length());
            System.err.println(fileShorName);
            fileNameMap.put(fileShorName, filePath);
        }
        while (true) {
            JarEntry originalJarEntry = (JarEntry) zis.getNextEntry();
            if (originalJarEntry == null)break;
            String jarEntryName = originalJarEntry.getName();
//            System.err.println(jarEntryName);
            int lastSeparatorIndex=jarEntryName.lastIndexOf(fileSlash);
            boolean isAbandonOringinal=false;
            String fileNameToBeAdd=null;
            if(lastSeparatorIndex<jarEntryName.length()){
                String jarEntryShortName=jarEntryName.substring(lastSeparatorIndex+1,jarEntryName.length());
//                System.err.println(jarEntryShortName);
                if(fileNameMap.keySet().contains(jarEntryShortName)){
                    isAbandonOringinal=true;
                    fileNameToBeAdd=fileNameMap.get(jarEntryShortName);
                    fileNameMap.remove(jarEntryShortName);
                }
            }
            if(isAbandonOringinal){
                addFileToJar(zos, fileNameToBeAdd, jarEntryName);
                continue;
            }
            JarEntry newJarEntry=new JarEntry(jarEntryName);
            zos.putNextEntry(newJarEntry);
            newJarEntry.setTime(originalJarEntry.getTime());
            copyStream(zis, zos,false);
        }
        Iterator<String> it=fileNameMap.keySet().iterator();
        while (it.hasNext()) {
            String fileShortName=it.next();
            String fileName=fileNameMap.get(fileShortName);
            addFileToJar(zos, fileName, fileShortName);
        }
        zos.finish();
    }
    
    private static void addFileToJar(JarOutputStream zos,String fileNameToBeAdd,String jarEntryName) throws IOException{
        JarEntry newJarEntry=new JarEntry(jarEntryName);
        zos.putNextEntry(newJarEntry);
        System.out.printf("Add file (%s) to (%s)\n",fileNameToBeAdd,jarEntryName);
        File fileToBeAdd=new File(fileNameToBeAdd);
        FileInputStream fis=new FileInputStream(fileToBeAdd);
        copyStream(fis,zos,false);
        newJarEntry.setTime(fileToBeAdd.lastModified());
    }
    
    @SuppressWarnings("unchecked")
    public static void mergeJarFile(String addTarget,String toAdd,String outputFile) throws Throwable, IOException{
        JarOutputStream zos = new JarOutputStream(new FileOutputStream(outputFile));
        JarFile jf=new JarFile(toAdd);
        List<String> fileExclude=new ArrayList<String>();
        Enumeration<JarEntry> e=jf.entries();
        while(e.hasMoreElements()){
            fileExclude.add(e.nextElement().getName());
        }
        writeFileDest(new JarInputStream(new FileInputStream(addTarget)),zos,fileExclude);
        System.out.println("Reday to deploy file(s):"+fileExclude.toString());
        writeFileDest(new JarInputStream(new FileInputStream(toAdd)),zos,Collections.EMPTY_LIST);
        zos.finish();
    
    }
    
    private static void writeFileDest(JarInputStream zis,JarOutputStream zos,List<String> excludeFileNames) throws Throwable{
        while (true) {
            JarEntry ze = (JarEntry) zis.getNextEntry();
            if (ze == null)
                break;
            String name = ze.getName();
//            System.err.println(name);
            if(excludeFileNames.contains(name))continue;
            JarEntry je=new JarEntry(ze.getName());
            je.setTime(ze.getTime());
            zos.putNextEntry(je);
                    byte[] buffer = new byte[1024];
                    while (true) {
                        int readSize = zis.read(buffer);
                        if (readSize == -1) break;
                        zos.write(buffer, 0, readSize);
                    }
                    zos.closeEntry();
        }
    }
    
    public static void copyFile(String src,String dest) throws IOException{
        if(src==null){
            throw new IllegalArgumentException("");
        }
        if(dest==null){
            throw new IllegalArgumentException("");
        }
        copyFile(new File(src),new File(dest));
    }
    
    public static void copyFile(File src,File dest) throws IOException{
        if(src==null){
            throw new IllegalArgumentException("");
        }
        if(dest==null){
            throw new IllegalArgumentException("");
        }
        if(!src.exists()){
            throw new IllegalArgumentException("");
         }
        boolean isDirectory=src.isDirectory();
        if(!dest.exists()){
            if(isDirectory){
                dest.mkdirs();
            }else{
                if(!dest.getParentFile().exists()){
                    dest.getParentFile().mkdirs();
                }
                dest.createNewFile();
            }
        }
        if(!isDirectory){
            System.err.println("copying file("+src.getAbsolutePath()+") to "+dest.getAbsolutePath());
            copyStream(new FileInputStream(src),new FileOutputStream(dest));
        }else{
           String[] subDirectories= src.list();
           for(String file:subDirectories){
               copyFile(src.getAbsolutePath()+File.separator+file,dest.getAbsolutePath()+File.separator+file);
           }
        }
        dest.setLastModified(src.lastModified());
    }
    
    public static void copyStream(InputStream is,OutputStream os) throws IOException{
        copyStream(is, os, true);
    }
    
    public static void copyStream(InputStream is,OutputStream os,boolean closeAfterFinsh) throws IOException{
        byte[] buffer=new byte[3072];
        while(true){
            int byteReaded=is.read(buffer);
            if(byteReaded==-1)break;
            os.write(buffer, 0, byteReaded);
        }
        os.flush();
        if(closeAfterFinsh){
            os.close();
        }
    }
    
    public static List<String> getInnerJarFile(String fileName) throws IOException{
        File dummyFile=new File(fileName);
        if(!(dummyFile.exists()&&dummyFile.isFile())){
            throw new IllegalArgumentException("");
        }
        JarFile jf=new JarFile(fileName);
        Enumeration<JarEntry> enumeration=jf.entries();
        List<String> result=new ArrayList<String>();
        while(enumeration.hasMoreElements()){
            String name=enumeration.nextElement().getName();
            if(name.endsWith(".jar")||name.endsWith(".ear")||name.endsWith(".war")){
                result.add(name);
            }
        }
        return result;
    }
    

	public static boolean isExists(String filePath) {
		return new File(filePath).exists();
	}

	public static boolean checkExtension(String filePath,List<String> fileExtensions) {
		if (filePath == null) {
			return false;
		}
		if (fileExtensions == null || fileExtensions.size() == 0) {
			return true;
		}
		int lastIndex=filePath.lastIndexOf(".");
		if (lastIndex< 0||lastIndex==filePath.length()) {
			return false;
		}
		return fileExtensions.contains(filePath.substring(lastIndex+1, filePath.length()));
	}
	
	public static boolean isJarFile(String filePath){
		List<String> jarFileExtensions=new ArrayList<String>();
		jarFileExtensions.add("jar");
		jarFileExtensions.add("ear");
		jarFileExtensions.add("war");
		return checkExtension(filePath,jarFileExtensions);
	}

}
